﻿using GuanQL.Core;
using GuanQL.Core.Domain.Accounts;
using GuanQL.Core.Multitenancy;
using GuanQL.Core.Stores;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Security.Claims;
using ZhongJia.Core;
using ZhongJia.Core.Caching;

namespace GuanQL.Service
{
    public class DefaultTenantResolver : ITenantResolver
    {
        private readonly HttpContext _httpContext;
        private static readonly string _TenantIdParam = "TenantId";
        private readonly ICacheClient _cacheClient;
        private readonly GQLDbContext _dbContext;

        public DefaultTenantResolver(
             IHttpContextAccessor httpContextAccessor,
             ICacheClient cacheClient,
            GQLDbContext dbContext)
        {
            _httpContext = httpContextAccessor.HttpContext;
            _cacheClient = cacheClient;
            _dbContext = dbContext;
        }

        private TenantModel _cacheTenant;

        public TenantModel GetTenant()
        {
            if (_cacheTenant != null)
                return _cacheTenant;

            Guid tenantId;
            if (_httpContext.User.Identity.IsAuthenticated)
            {
                _cacheTenant = GetTeantModel(Guid.Parse(_httpContext.User.Claims.First(c => c.Type == ClaimTypes.UserData).Value));
            }
            else if (
                _httpContext.Request.Headers.ContainsKey(_TenantIdParam) &&
                Guid.TryParse(_httpContext.Request.Headers[_TenantIdParam].First(), out tenantId))
            {
                if (!_httpContext.Request.Headers.ContainsKey(_TenantIdParam))
                    throw new UserFriendlyException("参数错误");

                _cacheTenant = GetTeantModel(tenantId);
            }
            if (_cacheTenant == null)
                throw new UserFriendlyException("参数错误");

            return _cacheTenant;
        }

        private TenantModel GetTeantModel(Guid tenantId)
        {
            return _cacheClient.GetOrCreate($"tenant_{ tenantId}", async () =>
            {
                var tenant = await _dbContext.Set<Tenant>().FirstOrDefaultAsync(t => t.TenantId == tenantId);
                return tenantId == null ? null : new TenantModel(tenant);
            }).Result;
        }
    }
}
